package com.thp.singleton;
/**
 * 懒汉单例  双重锁检查  (Double Check Lock)
 * @author Tommy
 *
 */
public class Singleton3 {

	
	private Singleton3() {}
	
	private static Singleton3 single = null;
	
	// 为了保证多线程线程安全的一种实现方式  双重锁检查
	public static Singleton3 getInstance() {
		/**
		 * DCL模式的优点就是:只有在对象需要被使用的时候才创建,第一次判断  INSTANCE == null  是为了避免非必要加锁
		 * 当第一次加载时进行加锁再实例化.这样既可以节约内存空间,又可以保证线程安全
		 * 但是由于jvm存在 乱序执行  功能, DCL也会出现线程不安全的情况
		 */
		if(single == null) {
			synchronized (Singleton3.class) {
				if(single == null) {
					/**
					 * 这个步骤,其实在JVM中的执行是分为三步:
					 *   1. 在内存中开辟空间
					 *   2. 在堆内存中实例化Singleton3里面的各个参数
					 *   3. 把对象执行内存堆空间
					 *   
					 *   但是由于jvm存在乱序执行功能,所以可能在2还没执行的时候就先执行3,如果此时再被切换到另一个线层上
					 *   由于已经执行了3,那么INSTANCE此时就不是null了,那么就会直接拿出来用,这样的话,就会出现异常.
					 *   这个就是著名的人DCL失效问题
					 *   
					 *   不过在JDK1.5之后,官方也发现了这个问题,故而具体化了volatie,即在JDK1.6及以后
					 *   只要定义为  private volatile static Singleton INSTANCE = null;  就可以解决DCL失效问题.
					 *   volatile确保INSTANCE每次均在主内存中读取,这样虽然会牺牲一点效率,但是也无伤大雅
					 */
					single = new Singleton3();
					
				}
			}
		}
		return single;
	}
	
	
	
}
